import json
import os
from datetime import datetime

from decimal import Decimal

from alipay import AliPay
from django import http
from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import JsonResponse
from django.shortcuts import render

# Create your views here.
from django.views import View
from django_redis import get_redis_connection

from apps.carts.models import OrderInfo, OrderGoods, Payment
from apps.goods import models
from apps.goods.models import SKU
from apps.users.models import Address
from apps.users.utils import CookieSecret
from utils.response_code import RETCODE
# from utils.scert import SecretOauth


class PaymentStatusView(View):
    def get(self, request):
        query_dict = request.GET
        print(query_dict, type(query_dict), "**************************************")
        data = query_dict.dict()
        print(data, type(data), "**************************************")
        signature = data.pop('sign')
        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=None,
            app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/app_private_key.pem"),
            alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                                "keys/alipay_public_key.pem"),
            sign_type="RSA2",
            debug=settings.ALIPAY_DEBUG)
        success = alipay.verify(data, signature)
        if success:
            # 读取order_id
            order_id = data.get('out_trade_no')
            # 读取支付宝流水号
            trade_id = data.get('trade_no')
            # 保存Payment模型类数据
            Payment.objects.create(
                order_id=order_id,
                trade_id=trade_id
            )

            # 修改订单状态为待评价
            OrderInfo.objects.filter(order_id=order_id, status=OrderInfo.ORDER_STATUS_ENUM['UNPAID']).update(
                status=OrderInfo.ORDER_STATUS_ENUM["UNCOMMENT"])

            # 响应trade_id
            context = {
                'trade_id': trade_id
            }
            return render(request, 'pay_success.html', context)
        else:
            # 订单支付失败，重定向到我的订单
            return http.HttpResponseForbidden('非法请求')

class PaymentView(LoginRequiredMixin, View):
    def get(self,request, order_id):
        # 查询要支付的订单
        user = request.user
        try:
            order = OrderInfo.objects.get(order_id=order_id, user=user, status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'])
        except OrderInfo.DoesNotExist:
            return http.HttpResponseForbidden('订单信息错误')

        # 创建支付宝支付对象
        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=None,  # 默认回调url
            app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/app_private_key.pem"),
            alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/alipay_public_key.pem"),
            sign_type="RSA2",
            debug=settings.ALIPAY_DEBUG
        )

        # 生成登录支付宝连接
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=order_id,
            total_amount=str(order.total_amount),
            subject="美多商城%s" % order_id,
            return_url=settings.ALIPAY_RETURN_URL,
        )

        # 响应登录支付宝连接
        # 真实环境电脑网站支付网关：https://openapi.alipay.com/gateway.do? + order_string
        # 沙箱环境电脑网站支付网关：https://openapi.alipaydev.com/gateway.do? + order_string
        alipay_url = settings.ALIPAY_URL + "?" + order_string
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'alipay_url': alipay_url})

# 提交订单成功后页面
class OrderSuccessView(LoginRequiredMixin, View):
    def get(self, request):
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')

        context = {
            'order_id': order_id,
            'payment_amount': payment_amount,
            'pay_method': pay_method
        }
        return render(request, 'order_success.html', context)

class OrderCommitView(LoginRequiredMixin, View):
    """订单提交
    思路：1.通过user.id从购物车中选取选中的商品信息
         2. 遍历商品信息 2.1 判断商品数量是否充足，如果充足存入数据库


    """
    def post(self, request):
        """保存订单信息和订单商品信息"""
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')
        if not all([address_id, pay_method]):
            return http.HttpResponseForbidden('缺少必要的参数')
        try:
            address = Address.objects.get(id=address_id)
        except Exception:
            return http.HttpResponseForbidden('参数addree_Id错误')
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'],OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.HttpResponseForbidden('参数pay_method错误')
        user = request.user
        order_id = datetime.now().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)
        from django.db import transaction
        # 事物开启
        with transaction.atomic():
            save_id = transaction.savepoint()
            # 事物保存节点
            try:
                order = OrderInfo.objects.create(
                    order_id = order_id,
                    user = user,
                    address = address,
                    total_count = 0,
                    total_amount = Decimal('0'),
                    freight = Decimal('10.00'),
                    pay_method = pay_method,
                    status = OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNSEND']

                )
                redis_client = get_redis_connection('carts')
                carts_data = redis_client.hgetall(user.id)
                carts_dict = {}
                for key,value in carts_data.items():
                    sku_id = int(key.decode())
                    sku_dict = json.loads(value.decode())
                    if sku_dict['selected']:
                        carts_dict[sku_id] = sku_dict
                sku_ids = carts_dict.keys()
                for sku_id in sku_ids:
                    while True:

                        sku = SKU.objects.get(id=sku_id)
                        origin_sales = sku.sales
                        origin_stock = sku.stock
                        cart_count = carts_dict[sku_id]['count']
                        if cart_count > sku.stock:
                            transaction.savepoint_rollback(save_id)
                            return JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})
                            # sku减少库存, 增加销量
                        # sku.stock -= cart_count
                        # sku.sales += cart_count
                        # sku.save()
                        # sku.spu.sales += cart_count
                        # sku.spu.save()
                        new_stock = origin_stock - cart_count
                        new_sales = origin_sales + cart_count
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock,sales=new_sales)
                        print('&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&')
                        i = 0
                        i = i + 1
                        print(i, result)
                        if result == 0:
                            continue

                         # SPU 增加销量
                        sku.spu.sales += cart_count
                        sku.spu.save()

                        # 保存订单商品信息
                        OrderGoods.objects.create(
                            order = order,
                            sku = sku,
                            count = cart_count,
                            price = sku.price
                        )
                        order.total_count += cart_count
                        order.total_amount += (cart_count*sku.price)
                        break

                order.total_amount += order.freight
                order.save()
            except:
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'code': RETCODE.OK, 'errmsg': '下单失败'})
            transaction.savepoint_commit(save_id)
        redis_client.hdel(user.id, *carts_dict)
        # 返回响应结果
        return JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order.order_id})


class OrderSettlementView(LoginRequiredMixin, View):
    """结算订单"""

    def get(self, request):
        """提供订单结算页面"""
        user = request.user
        try:
            from apps.users.models import Address
            addresses = Address.objects.filter(user=user, is_deleted=False)
        except:
            addresses = None
        redis_client = get_redis_connection('carts')
        cart_data = redis_client.hgetall(user.id)
        carts_dict = {}
        for key, value in cart_data.items():
            sku_id = int(key.decode())
            sku_dict = json.loads(value.decode())
            if sku_dict['selected']:
                carts_dict[sku_id] = sku_dict
        # 计算金额
        total_count = 0
        total_amount = Decimal(0.00)
        skus = SKU.objects.filter(id__in=carts_dict.keys())
        for sku in skus:
            sku.count = carts_dict[sku.id].get('count')
            sku.amount = sku.count*sku.price
            total_count += sku.count
            total_amount += sku.count * sku.price
        freight = Decimal('10.00')
        print('---------------------------------------------')
        print('---------------------------------------------')
        print(freight)
        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_amount + freight,
            'default_address_id': user.default_address_id
        }
        return render(request, 'place_order.html', context)


class CartsSimpleView(View):
    def get(self, request):
        user = request.user
        if user.is_authenticated:
            carts_redis_client = get_redis_connection('carts')
            carts_data = carts_redis_client.hgetall(user.id)
            cart_dict = {int(key.decode()): json.loads(value.decode()) for key, value in carts_data.items()}
        else:
            # 用户未登录，查询cookie购物车
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = CookieSecret.loads(cart_str)
            else:
                cart_dict = {}
        cart_skus = []
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'count': cart_dict.get(sku.id).get('count'),
                'default_image_url': sku.default_image.url
            })

        # 响应json列表数据
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'cart_skus': cart_skus})


class CartsSelectAllView(View):
    '''全选购物车'''
    def put(self, request):
        user = request.user
        json_dict = json.loads(request.body.decode())
        selected = json_dict.get('selected', True)
        if selected:
            if not isinstance(selected, bool):
                return http.HttpResponseForbidden('参数selected有错误')
        if user.is_authenticated:
            carts_redis_client = get_redis_connection('carts')
            carts_data = carts_redis_client.hgetall(user.id)
            for key, values in carts_data.items():
                sku_id = int(key.decode())
                carts_dict = json.loads(values.decode())
                carts_dict['selected'] = selected
                carts_redis_client.hset(user.id, sku_id, json.dumps(carts_dict))
            return JsonResponse({'code': RETCODE.OK, 'errmsg': '全选购物车成功'})
        else:
            carts_str = request.COOKIES.get('carts')
            response = JsonResponse({'code': RETCODE.OK, 'errmsg': '全选购物车成功'})
            if carts_str is not None:
                carts_dict = CookieSecret.loads(carts_str)
                for sku_id in carts_dict:
                    carts_dict[sku_id]['selected'] = selected
                cookie_cart = CookieSecret.dumps(carts_dict)
                response.set_cookie('carts',cookie_cart,24 * 30 * 3600)
            return  response


class CartsView(View):
    """购物车管理"""
    # 1.添加购物车
    def post(self, request):
        """添加购物车"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')
        count = json_dict.get('count')
        selected = json_dict.get('selected', True)

        # 判断参数是否齐全
        if not all([sku_id, count]):
            return http.HttpResponseForbidden('缺少必传参数')
        # 判断sku_id是否存在
        try:
            models.SKU.objects.get(id=sku_id)
        except models.SKU.DoesNotExist:
            return http.HttpResponseForbidden('商品不存在')
        # 判断count是否为数字
        try:
            count = int(count)
        except Exception:
            return http.HttpResponseForbidden('参数count有误')
        # 判断selected是否为bool值
        if selected:
            if not isinstance(selected, bool):
                return http.HttpResponseForbidden('参数selected有误')

                # 判断用户是否登录
            user = request.user
            if user.is_authenticated:
                # 3.1 登录 使用redis存储
                carts_redis_client = get_redis_connection('carts')

                # 3.2 获取以前数据库的数据
                client_data = carts_redis_client.hgetall(user.id)

                # 如果商品已经存在就更新数据
                if str(sku_id).encode() in client_data:
                    # 根据sku_id 取出商品
                    child_dict = json.loads(client_data[str(sku_id).encode()].decode())
                    #  个数累加
                    child_dict['count'] += count
                    # 更新数据
                    carts_redis_client.hset(user.id, sku_id, json.dumps(child_dict))

                else:
                    # 如果商品已经不存在--直接增加商品数据
                    carts_redis_client.hset(user.id, sku_id, json.dumps({'count': count, 'selected': selected}))

                return JsonResponse({'code': RETCODE.OK, 'errmsg': '添加购物车成功'})
            else:
                # 用户未登录，操作cookie购物车
                cart_str = request.COOKIES.get('carts')
                # 如果用户操作过cookie购物车
                if cart_str:
                    # 解密出明文
                    cart_dict = CookieSecret.loads(cart_str)
                else:  # 用户从没有操作过cookie购物车
                    cart_dict = {}

                # 判断要加入购物车的商品是否已经在购物车中,如有相同商品，累加求和，反之，直接赋值
                if sku_id in cart_dict:
                    # 累加求和
                    origin_count = cart_dict[sku_id]['count']
                    count += origin_count
                cart_dict[sku_id] = {
                    'count': count,
                    'selected': selected
                }
                # 转成密文
                cookie_cart_str = CookieSecret.dumps(cart_dict)

                # 创建响应对象
                response = JsonResponse({'code': RETCODE.OK, 'errmsg': '添加购物车成功'})
                # 响应结果并将购物车数据写入到cookie
                response.set_cookie('carts', cookie_cart_str, max_age=24 * 30 * 3600)
                return response

    # 2.查询购物车
    def get(self, request):

        ''' 展示购物车 '''

        user= request.user
        if user.is_authenticated:

            # 1.用户已经登路，查询redis数据库
            cart_redis_client = get_redis_connection('carts')
            # 2.获取当前用户的所有购物车数据
            carts_data = cart_redis_client.hgetall(user.id)
            carts_dict = {}
            for key,value in carts_data.items():
                sku_id = int(key.decode())
                sku_dict = json.loads(value.decode())
                carts_dict[sku_id] = sku_dict

        else:
            cookie_str = request.COOKIES.get('carts')
            if cookie_str:
                carts_dict = CookieSecret.loads(cookie_str)
            else:
                carts_dict = {}
        sku_ids = carts_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        cart_skus = []
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'count': carts_dict.get(sku.id).get('count'),
                'selected': str(carts_dict.get(sku.id).get('selected')),  # 将True，转'True'，方便json解析
                'default_image_url': sku.default_image.url,
                'price': str(sku.price),  # 从Decimal('10.2')中取出'10.2'，方便json解析
                'amount': str(sku.price * carts_dict.get(sku.id).get('count')),
                })
        context = {
            'cart_skus': cart_skus,
        }
                # 渲染购物车页面
        return render(request, 'cart.html', context)

    # 3.修改购物车
    def put(self, request):
        user = request.user
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')
        count = json_dict.get('count')
        selected = json_dict.get('selected',True)
        cookie_cart_str = ''
        if not all([sku_id, count]):
            return http.HttpResponseForbidden('缺少必要的参数')
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden('商品sku_id不存在')
        # 判断count是否位数字
        try:
            count = int(count)
        except Exception:
            return http.HttpResponseForbidden('参数count有错误')
        # 判断selected是否为bool值
        if selected:
            if not isinstance(selected, bool):
                return http.HttpResponseForbidden('参数selected有错误')

        if user.is_authenticated:
            # 用户登录
           carts_redis_client = get_redis_connection('carts')
           new_data = {'count':count, 'selected':selected}
           carts_redis_client.hset(user.id, sku_id, json.dumps(new_data))
        else:
            # 用户未登录时

            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = CookieSecret.loads(cart_str)
            else:
                cart_dict = []
            cart_dict[sku_id] = {'count':count,
                         'selected':selected}
            # 转换成 密文数据
            cookie_cart_str = CookieSecret.dumps(cart_dict)
        cart_sku = {
            'id':sku_id,
            'count':count,
            'selected':selected,
            'name':sku.name,
            'default_image_url':sku.default_image.url,
            'price':sku.price,
            'amount':sku.price*count

        }
        response = JsonResponse({'code': RETCODE.OK, 'errmsg': '修改购物车成功', 'cart_sku': cart_sku})
        if not user.is_authenticated:
             response.set_cookie('carts', cookie_cart_str)

        return response

    # 删除购物车
    def delete(self, request):
        '''删除购物车'''
        # 1.接受参数
        # 2.判断用户是否登录

        user = request.user
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')
        if user.is_authenticated:
            carts_redis_client = get_redis_connection('carts')
            carts_redis_client.hdel('user_id', 'sku_id')
            return JsonResponse({'code': RETCODE.OK, 'errmsg': '删除购物车成功'})
        else:
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = CookieSecret.loads(cart_str)
            else:
                cart_dict = {}
            response = JsonResponse({'code': RETCODE.OK, 'errmsg': '删除购物车成功'})
            if sku_id in cart_dict:
                del cart_dict[sku_id]
                cookie_cart_str = CookieSecret.dumps(cart_dict)
                response.set_cookie('carts', cookie_cart_str, max_age=24*30*3600)
            return response



